﻿using System;
using System.Collections.Generic;
using System.Web;
using DecisionMaking.BusinessLogic;
using DecisionMaking.BusinessLogic.Model;
using MvcContrib;
using System.Web.Mvc;

namespace DecisionMaking.WebApp.Controllers
{
    [HandleError]
    [Authorize]
    public class AlgorithmsController : BaseController
    {
        /// <summary>
        /// Injected by Windsor 
        /// </summary>
        public IAlgorithmManager AlgorithmManager { private get; set; }	

        [HttpGet]
        public ActionResult Index()
        {
            var algorithms = AlgorithmManager.GetAlgorithmDefinitions(CurrentAccount.Id);
            return View("List", algorithms);
        }

        [HttpGet]
        public ActionResult Add()
        {
            ViewData["engines"] = AlgorithmManager.GetEngineNames();

            // prepare the algorithm template
            var template = 
@"/**
 * The following variables are available:
 *
 * agent - Agent
 * cues - IList<Cue>, use cues.GetValue(i) to access an individual cue; cues[i] will not work.
 * left, right - Candidate
 *
 * Use agent.Recognizes(candidate) to check for recognition of a specific candidate.
 * Use agent.GetCuevValue(candidate, cue) to retrieve a specific cue value for that candidate; note that 
 * if the candidate or the cue are not recognized or the , this will return null. A Cue's attributes may be
 * queried by calling cue.GetAttributeValue(name). For instance, in order to retrieve the value for Ecological 
 * Validity, call cue.GetAttributeValue('Ecological Validity');
 * For adaptive algorithms, you may use agent.Context as a key/value store
 */

var result;
var cuesUsed = 0;
var candidatesRecognized = 0;

return new DecisionMaking.BusinessLogic.AlgorithmResult(result, cuesUsed, candidatesRecognized);
            ";

            return View("Edit", new AlgorithmDefinitionModel { AccountId = CurrentAccount.Id, Code = template});
        }

        [HttpGet]
        public ActionResult Clone(int id)
        {
            var algorithmDefinition = AlgorithmManager.GetAlgorithmDefinition(id);

            var model = new AlgorithmDefinitionModel
            {
                DefinitionId = null,
                AccountId = CurrentAccount.Id,
                Engine = algorithmDefinition.Engine,
                Code = algorithmDefinition.Code
            };

            ViewData["engines"] = AlgorithmManager.GetEngineNames();

            return View("Edit", model);
        }

        [HttpGet]        
        public ActionResult Edit(int id)
        {
            var algorithmDefinition = AlgorithmManager.GetAlgorithmDefinition(id);

            // make sure current user is owner of current algorithm
            if (!algorithmDefinition.Account.Equals(CurrentAccount))
            {
                return AccessDenied();
            }

            var model = new AlgorithmDefinitionModel
            {
                DefinitionId = algorithmDefinition.Id,                
                AccountId = algorithmDefinition.Account.Id,
                Name = algorithmDefinition.Name,
                Engine = algorithmDefinition.Engine,
                Code = algorithmDefinition.Code
            };

            ViewData["engines"] = AlgorithmManager.GetEngineNames();
            return View("Edit", model);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Save(AlgorithmDefinitionModel model)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    AlgorithmManager.SaveAlgorithmDefinition(model);

                    return this.RedirectToAction("Index");
                }
                catch (AlgorithmCompilationException e)
                {
                    ModelState.AddModelError("Code", e.Data["errors"].ToString());
                }
                catch (DuplicateAlgorithmDefinitionNameException e)
                {
                    ModelState.AddModelError("Name", e.Message);
                }
                catch (AccessDeniedException e)
                {
                    return AccessDenied(e);
                }
                catch (EntityNotFoundException e)
                {
                    return NotFound(e);
                }
            }

            ViewData["engines"] = AlgorithmManager.GetEngineNames();
            return View("Edit", model);            
        }

    }
}
